#include "stdafx.h"
#include "LoAg.h"
#include <io.h>

#include <Objbase.h>

typedef HRESULT (WINAPI *PDllGetClassObject)( const CLSID & rclsid, const IID & riid, void ** ppv ); 

/*!
\brief One registered COM object in our collection.

The COM object must expose the IDispatch interface.
*/
class LoAgCom
{
public:
	LoAgCom( wchar_t const *path )
	{
		moduleHandle_ = LoadLibrary( path );
		if( moduleHandle_ )
		{
			pDllGetClassObject_ = (PDllGetClassObject)GetProcAddress( moduleHandle_, "DllGetClassObject" );
		}
		else
		{
			pDllGetClassObject_ = NULL;
		}
		next_ = NULL;
	}
	~LoAgCom()
	{
		if( NULL != moduleHandle_ )
		{
			FreeLibrary( moduleHandle_ );
		}
	}
	HRESULT DllGetClassObject( const CLSID & rclsid, const IID & riid, void ** ppv )
	{
		return pDllGetClassObject_( rclsid, riid, ppv );
	}
	LoAgCom	*getNext()
	{
		return next_;
	}
	bool isValid()
	{
		return pDllGetClassObject_ != NULL;
	}
	void setNext( LoAgCom *next )
	{
		next_ = next;
	}
private:
	LoAgCom				*next_;
	HMODULE				moduleHandle_;
	PDllGetClassObject	pDllGetClassObject_;
	BSTR				progId_;
};

/*!
\brief 
*/
class LoAgComCollection
{
public:
	LoAgComCollection()
	{
		collection_ = NULL;
	}
	~LoAgComCollection()
	{
		clear();
	}
	/*!
	\brief clears (resets) the collection.
	*/
	void clear()
	{
		LoAgCom	*loAgComNext = NULL;
		for( LoAgCom *loAgCom = collection_; loAgCom != NULL; loAgCom = loAgComNext )
		{
			loAgComNext = loAgCom->getNext();
			delete loAgCom;
		}
	}
	/*!
	\brief Scans a directory and registers all the COM objects found there.
	@param[in]	directory	Directory
	\retval HRESULT	S_OK(0) on success
	*/
	void registerDirectory( wchar_t const *directory )
	{
		_wfinddata64i32_t findData;
		intptr_t findHandle = _wfindfirst( directory, &findData );
		if( findHandle != ((intptr_t)-1) )
		{
			for( int failure = 0; !failure;	failure = _wfindnext( findHandle, &findData ) )
			{
				wchar_t		fullPath[_MAX_PATH];
				_wmakepath( fullPath, NULL, directory, findData.name, NULL );
				registerDll( fullPath );
			}
			_findclose( findHandle );
		}
	}
	LoAgCom *registerDll( wchar_t const *path )
	{
		LoAgCom	*loAgCom = new LoAgCom( path );
		if( loAgCom->isValid() )
		{
			loAgCom->setNext(collection_);
			collection_ = loAgCom;
		}
		else
		{
			delete	loAgCom;
			loAgCom = NULL;
		}
		return loAgCom;
	}
private:
	LoAgCom		*collection_;
};
